/*******************************************************************************
 * Copyright (c) 2009, 2021 GMT Corp., Nicholas Yu and others
 *
 * All rights reserved. 
 *
 * Description:
 *    gmt iot sdk interface
 * 
 * Contributors:
 *    Nicholas Yu - initial API and implementation
 * 
 *******************************************************************************/

#ifndef SDK_H
#define SDK_H

#include <string>
#include <functional>
#include "sdk_def.h"

namespace gmtiot
{
    class sdk
    {
    public:

        virtual ~sdk() {}

        /**
         * @brief sdk通过单例模式使用，所以调用任何接口之前先get()获取实例
         *          例如： sdk::get().debugFlag(false).filePath("/data/cache")
         * @return sdk单例引用
         */
        static sdk &get();

        /**
         * @brief sdk version
         * 
         * @return sdk& 
         */
        virtual const string &version() = 0;

        /**
         * @brief 设置调试模式
         * @param debugFlag true/false
         * @return sdk单例引用
         */
        virtual sdk &debugFlag(bool debugFlag) = 0;

        /**
         * @brief 设置sdk产生的缓存文件存储位置
         * @param path 存储文件路徑
         * @return sdk单例引用
         */
        virtual sdk &filePath(const string &path) = 0;

        /**
         * @brief 用户侧专用接口 - 设置用户端的userToken
         * @param userToken 用户登录返回的令牌
         * @return sdk单例引用
         */
        virtual sdk &userToken(const string &userToken) = 0;

        /**
         * @brief 设置clientId，在GMT云平台注册获取
         * @param clientId 注册的客户Id
         * @return sdk单例引用
         */
        virtual sdk &clientId(const string &clientId) = 0;

        /**
         * @brief 设置clientSecret，在GMT云平台注册获取
         * @param clientSecret 注册的客户密钥
         * @return sdk单例引用
         */
        virtual sdk &clientSecret(const string &clientSecret) = 0;

        /**
         * @brief 设备侧专用接口 - 设置deviceId，通常是mac地址或者sn号，需要保证唯一性
         * @param deviceId 设备唯一id
         * @return sdk单例引用
         */
        virtual sdk &deviceId(const string &deviceId) = 0;

        /**
         * @brief 设备侧专用接口 - 设置typeId，在GMT云平台创建产品后生成
         * @param typeId GMT云平台创建的产品ID
         * @return sdk单例引用
         */
        virtual sdk &typeId(const string &typeId) = 0;

        /**
         * @brief 设备侧专用接口 - 设置modelCode，在GMT云平台创建产品后生成的型号编码
         * @param modelCode GMT云平台创建的产品后生成的型号编码
         * @return sdk单例引用
         */
        virtual sdk &modelCode(const string &modelCode) = 0;

        /**
         * @brief 设备侧专用接口 - 设置需要升级的软件版本信息
         * @param versions 需要升级的软件版本信息
         * @return sdk单例引用
         */
        virtual sdk &otaVersion(list<PackageVersion> &versions) = 0;

        /**
         * @brief 设备侧专用接口 - 设置经纬度
         * @param lo 经度
         * @param la 纬度
         * @return sdk单例引用
         */
        virtual sdk &position(double lo, double la) = 0;

        /**
         * @brief sdk初始化
         * @return sdk单例引用
         */
        virtual sdk &init() = 0;

        /**
         * @brief sdk销毁释放资源，release后不可再使用，通常在退出程序前调用
         * @return 无
         */
        virtual void release() = 0;

        /**
         * @brief 用户侧专用接口 - 用户端调用此接口连接云平台
         *        注意：如果没有设置userToken，调用appConnect后仍需要调用updateToken(token)设置用户登录令牌之后才能连接成功
         * @param callback 用户端sdk回调函数接口
         * @return sdk单例引用
         */
        virtual sdk &appConnect(const app_callback_ptr &callback) = 0;

        /**
         * @brief 设备侧专用接口 - 设备端调用此接口连接云平台
         * @param callback 设备端sdk回调函数接口
         * @return sdk单例引用
         */
        virtual sdk &deviceConnect(const dev_callback_ptr &callback) = 0;

        /**
         * @brief 用户侧专用接口 - 更新用户登录token，更新后会自动重新连接云平台
         * @param userToken 用户登录令牌
         * @return true/false
         */
        virtual bool updateToken(const string &userToken) = 0;

        /**
         * @brief 用户侧专用接口 - 更新设备list
         * @return true/false
         */
        virtual bool updateDeviceList() = 0;

        /**
         * @brief 用户侧专用接口 - 检查应用端是否链接云平台成功
         * @return true/false
         */
        virtual bool isAppConnected() = 0;

        /**
         * @brief 设备侧专用接口 - 检查设备端是否链接云平台成功
         * @return true/false
         */
        virtual bool isDevConnected() = 0;

        /**
         * @brief 用户侧专用接口 - 订阅设备消息
         * @param deviceId 设备唯一Id
         * @return true/false
         */
        virtual bool subscribeDevice(const string &deviceId) = 0;

        /**
         * @brief 用户侧专用接口 - 取消订阅设备消息
         * @param deviceId 设备唯一Id
         * @return true/false
         */
        virtual bool unsubscribeDevice(const string &deviceId) = 0;

        /**
         * @brief 用户侧专用接口 - 设置设备参数
         * @param deviceId 设备唯一Id
         * @param name 参数名字
         * @param value 参数直
         * @return true/false
         */
        virtual bool setDeviceAttribute(const string &deviceId, const string &name, const string &value) = 0;

        /**
         * @brief 用户侧专用接口 - 设置设备参数
         * @param deviceId 设备唯一Id
         * @param values 一组参数键值对列表
         * @return true/false
         */
        virtual bool setDeviceAttribute(const string &deviceId, list<AttributeValue> &values) = 0;

        /**
         * @brief 用户侧专用接口 - 读取设备参数
         * @param deviceId 设备唯一id
         * @param name 参数名字
         * @return true/false
         */
        virtual bool getDeviceAttribute(const string &deviceId, const string &name) = 0;

        /**
         * @brief 用户侧专用接口 - 读取设备参数
         * @param deviceId 设备唯一id
         * @param names 参数列表，AttributeValue中只需要设置name，value忽略
         * @return true/false
         */
        virtual bool getDeviceAttribute(const string &deviceId, list<AttributeValue> &names) = 0;

        /**
         * @brief 设备侧专用接口 - 设备在参数变化后主动调用update接口上报新的参数值
         * @param attributes 变化的参数键值对列表
         * @return true/false
         */
        virtual bool updateDeviceAttribute(list<AttributeValue> &attributes) = 0;

        /**
         * @brief 设备侧专用接口 - 设备在收到用户端的读写消息后，需要调用此接口回复用户端读写结果
         * @param attributes 读写的参数键值对列表
         * @param msgId 读写的消息id，原样回复回去，用于处理消息一致性
         * @return true/false
         */
        virtual bool responseDeviceAttribute(list<AttributeValue> &attributes, const string &msgId) = 0;

        /**
         * @brief 用户侧专用接口 - 使用手机验证码登录的时候用于获取验证码
         * @param phoneNumber 手机号码
         * @param listener 登录结果回调接口函数
         * @return true/false
         */
        virtual bool loginRequestCode(const string &phoneNumber) = 0;

        /**
         * @brief 用户侧专用接口 - 受到验证码后使用手机号码和验证码登录
         * @param phoneNumber 手机号码
         * @param code 短信验证码
         * @param listener 登录结果回调函数
         * @return true/false
         */
        virtual bool loginByMsgCode(const string &phoneNumber, const string &code) = 0;

        /**
         * @brief 用户侧接口 - 绑定设备到用户帐号中
         * @param userToken 用户登录后令牌
         * @param deviceId 要绑定的设备唯一Id
         * @param typeId 设备产品id
         * @param modelCode 设备型号编码
         * @param listener 绑定结果回调函数
         * @return true/false
         */
        virtual bool bindDevice(const string &userToken, const string &deviceId, const string &typeId, const string &modelCode) = 0;

        /**
         * @brief 设备侧接口 - 通常只有网关设备使用，暂时不起用
         * @param userToken 用户登录令牌
         * @param listener 绑定结果回调函数
         * @return
         */
        virtual bool bindSelf(const string &userToken) = 0;

        /**
         * @brief 设备侧接口 - 启动配网流程
         * 
         * @param callback config callback
         * @return true 
         * @return false 
         */
        virtual bool startConfig(const config_callback_ptr &callback) = 0;

        /**
         * @brief 设备侧接口 - 停止配网流程
         * 
         * @return true 
         * @return false 
         */
        virtual bool stopConfig() = 0;

    };
}

#endif // SDK_H
